<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\App\WorkAgent\Listener;

use Hyperf\Di\Annotation\Inject;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Codec\Json;
use MoChat\App\Corp\Contract\CorpContract;
use MoChat\App\Corp\Utils\WeWorkFactory;
use MoChat\App\WorkAgent\Contract\WorkAgentContract;
use MoChat\App\WorkAgent\Event\CreateAuthRawEvent;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;

/**
 * 授权成功通知.
 *
 * @Listener(priority=9999)
 */
class CreateAuthRawListener implements ListenerInterface
{
    /**
     * @Inject
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var WeWorkFactory
     */
    private $weWorkFactory;

    /**
     * @var WorkAgentContract
     */
    private $workAgentService;

    /**
     * @var CorpContract
     */
    private $corpService;

    public function listen(): array
    {
        return [
            CreateAuthRawEvent::class,
        ];
    }

    public function process(object $event)
    {
        try {
            $message = $event->message;
            $loggerFactory = $this->container->get(LoggerFactory::class);
            $this->logger = $loggerFactory->get(__CLASS__);
            $this->weWorkFactory = $this->container->get(WeWorkFactory::class);
            $this->workAgentService = $this->container->get(WorkAgentContract::class);
            $this->corpService = $this->container->get(CorpContract::class);
            $this->logger->debug(sprintf('授权成功通知监听器开始，消息体为：%s', Json::encode($message)));

            $authCode = $message['AuthCode'];

            $openApp = $this->weWorkFactory->getProviderApp($message['SuiteId']);
            $wxResult = $openApp->corp->getPermanentByCode($authCode);

            if (isset($wxResult['errcode'])) {
                $this->logger->warning(sprintf('获取永久授权码失败，错误信息：%s', $wxResult['errmsg']));
                return;
            }

            if (($corpId = $this->getCorpId($wxResult)) > 0) {
                $this->createAgent($corpId, $wxResult);

                if (! empty($wxResult['auth_corp_info']) && ! empty($wxResult['auth_corp_info']['corpid'])) {
                    $this->corpService->updateCorpById($corpId, [
                        'open_wx_corpid' => $wxResult['auth_corp_info']['corpid'],
                        'auth_type' => 4,
                    ]);
                }
            }

            $this->logger->debug(sprintf('授权成功通知监听器执行成功'));
        } catch (\Throwable $e) {
            $this->logger->error(sprintf('授权成功通知回调监听器失败，错误信息：%s', $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
        }
    }

    private function getCorpId(array $wxResult)
    {
        if (empty($wxResult['state'])) {
            return 0;
        }

        if (! $this->hasCorpId($wxResult['state'])) {
            return 0;
        }

        $state = str_replace('corpId', '', $wxResult['state']);
        return (int) $state;
    }

    private function hasCorpId(string $state): bool
    {
        return strpos($state, 'corpId') !== false;
    }

    private function createAgent(int $corpId, array $wxResult)
    {
        $wxAgent = $wxResult['auth_info']['agent'][0];
        $agent = $this->workAgentService->getWorkAgentByCorpIdWxAgentId($corpId, (string) $wxAgent['agentid'], ['id']);

        $data = [
            'corp_id' => $corpId,
            'wx_agent_id' => $wxAgent['agentid'],
            'wx_secret' => $wxResult['permanent_code'],
            'name' => $wxAgent['name'],
            'type' => 1,
            'square_logo_url' => $wxAgent['square_logo_url'],
            'is_customized_app' => $wxAgent['is_customized_app'] ? 1 : 0,
            'privilege' => Json::encode($wxAgent['privilege']),
        ];

        if (empty($agent)) {
            $this->workAgentService->createWorkAgent($data);
        } else {
            $this->workAgentService->updateWorkAgentById($agent['id'], $data);
        }
    }
}
